#include "EventLoop.hpp"
#include "TcpConnection.hpp"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <sys/epoll.h>
using std::cout;
using std::endl;

namespace wd{


EventLoop::EventLoop(Acceptor & acceptor)
:_epfd(epollcreate())
,_acceptor(acceptor)
,_isLooping(false)
,_events(1000)
,_eventfd(eventfdCreate())
{
    addEpollReadEvent(_acceptor.listenfd());
    addEpollReadEvent(_eventfd);
}
    
void EventLoop::loop(){
    _isLooping = true;
    while(_isLooping){
        waitEpollfd();
    }
}
void EventLoop::unloop(){
    _isLooping = false;
}
    
void EventLoop::setAllCallbacks(const CallBack & onNewConnection
                         ,const CallBack & onMessage
                         ,const CallBack & onClose){
    _onNewConnection = onNewConnection;
    _onMassage = onMessage;
    _onClose = onClose;
}

int EventLoop::epollcreate(){
    int epfd = epoll_create1(0);
    if(epfd < 0){
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }
    return epfd;
}

void EventLoop::waitEpollfd(){
    int readynum = epoll_wait(_epfd,_events.data(),1000,5000);
    if(readynum == -1 && errno == EINTR){
        return; 
    }else if(readynum == -1){
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }else if(readynum == 0){
        printf("epoll_time timeout\n");
    }else{
        for(int i =0 ;i<readynum; ++i){
            int fd = _events[i].data.fd;
            if(fd == _acceptor.listenfd()){
               handleNewConnection(); 
            }
            else if(fd == _eventfd){
                printf("happened a eventfd");
                handleReadEvent();
                doPendingFunctors();
            }
            else{
                handleMessage(fd);
            }
        }
    }

}

void EventLoop::handleNewConnection(){
    int clientfd = _acceptor.accept();
    if(clientfd < 0){
        perror("accept");
        return;
    }
    addEpollReadEvent(clientfd);
    _conns.insert(std::make_pair(clientfd,
                                TcpConnectionptr(new TcpConnection(clientfd,this))));
    _onNewConnection(_conns[clientfd]);
}

void EventLoop::handleMessage(int fd){
    auto it = _conns.find(fd);
    if(it != _conns.end()){
        if(_conns[fd]->isClose()){
            //对面断开连接
            delEpollReadEvent(fd);
            _onClose(_conns[fd]);
        }else{
           //处理对方发来的信息 
           _onMassage(_conns[fd]);
        }
    }
}

void EventLoop::addEpollReadEvent(int clientfd){
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = clientfd;
    epoll_ctl(_epfd,EPOLL_CTL_ADD,clientfd,&ev);
}

void EventLoop::delEpollReadEvent(int clientfd){
    struct epoll_event ev;
    ev.data.fd = clientfd;
    epoll_ctl(_epfd,EPOLL_CTL_DEL,clientfd,&ev);
}

//关于eventfd的相关实现
void EventLoop::addFunctor(Functor && functor){
    std::unique_lock<mutex> _ul(_mutex);
    _pendingFunctors.push_back(std::move(functor));

    wakeup(); //通知主线程执行send事件
}

int EventLoop::eventfdCreate(){
    int ret = eventfd(0,0);
    if(ret < 0){
        perror("eventfd");
        exit(EXIT_FAILURE);
    }
    return ret;
}

void EventLoop::wakeup(){
    uint64_t howmany = 1;
    int ret = write(_eventfd,&howmany,sizeof(howmany));
    if(ret != sizeof(howmany)){
        perror("write");
        //exit(EXIT_FAILURE);
    }
}
    
void EventLoop::handleReadEvent(){
    uint64_t howmany = 0;
    int ret = read(_eventfd,&howmany,sizeof(howmany));
    if(ret != sizeof(howmany)){
        perror("read");
        //exit(EXIT_FAILURE);
    }
}
    
void EventLoop::doPendingFunctors(){
    printf("do pending functors \n");
    vector<Functor> temp;
    {
    std::unique_lock<mutex> ul(_mutex); 
    temp.swap(_pendingFunctors);
    }
    for(auto & f: temp){
        f();
    }
    
}

}
